package com.maolong.api.doc;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.maolong.util.JsonObjUtil;
import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.FuzzyQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 封装查询的接口
 */
public class EsDocQueryUtil  {

    private static final String HOST = "localhost";
    private static final int PORT = 9200;
    private static final String SCHEME = "http";
    private static RestHighLevelClient client;
    private static ObjectMapper objectMapper=new ObjectMapper();

    static {
        client=new RestHighLevelClient(
                RestClient.builder(new HttpHost(HOST,PORT,SCHEME)));
    }

    /**
     * 获取单条文档
     * @param indexName
     * @param id
     * @return
     */
    public static GetResponse getDoc(String indexName, String id){
        GetRequest getRequest=new GetRequest();
        getRequest.index(indexName).id(id);
        try {
            return client.get(getRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询所有的数据,转化为真实的对象
     */
    public static <T> List<T> getAllDoc(String indexName,Class<T> tClass){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        return getResults(searchSourceBuilder,indexName,tClass);
    }

    /**
     * 根据关键term
     */
    public static <T> List<T> termDoc(String indexName,Class<T> tClass){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.termQuery("name","term"));
        return getResults(searchSourceBuilder,indexName,tClass);
    }

    /**
     * 分页查询
     */
    public static <T> List<T> pageDoc(String indexName,Class<T> tClass,int page,int size){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.from(page).size(size);
        return getResults(searchSourceBuilder,indexName,tClass);
    }
    /**
     * 数据排序
     */
    public static <T> List<T> sortDoc(String indexName,Class<T> tClass, String sortField,boolean isAsc){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.sort(sortField,isAsc? SortOrder.ASC: SortOrder.DESC);
        return getResults(searchSourceBuilder,indexName,tClass);
    }

    /**
     *过滤字段
     */
    public static <T> List<T> filterDoc(String indexName,Class<T> tClass,String[] includes,String[] excludes){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.fetchSource(includes,excludes);
        return getResults(searchSourceBuilder,indexName,tClass);
    }
    /**
     * bool查询,todo 此处可以重载
     */
    public static <T> List<T> boolDoc(String indexName, Class<T> tClass, Map<String,String> must,
                                      Map<String,String> mustNot,Map<String,String> should){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();
        must.forEach((k,v)-> {boolQueryBuilder.must(QueryBuilders.matchQuery(k, v));});
        mustNot.forEach((k,v)-> {boolQueryBuilder.mustNot(QueryBuilders.matchQuery(k, v));});
        should.forEach((k,v)-> {boolQueryBuilder.should(QueryBuilders.matchQuery(k, v));});
        searchSourceBuilder.query(boolQueryBuilder);
        return getResults(searchSourceBuilder,indexName,tClass);

    }
    /**
     * 范围查询
     */
    public static <T> List<T> rangeDoc(String indexName, Class<T> tClass,String field,Number from,Number to){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        RangeQueryBuilder rangeQueryBuilder=new RangeQueryBuilder(field);
        rangeQueryBuilder.gte(from).lte(to);
        searchSourceBuilder.query(rangeQueryBuilder);
        return getResults(searchSourceBuilder,indexName,tClass);
    }

    /**
     * 模糊查询
     */
    public static <T> List<T> fuzzyDoc(String indexName, Class<T> tClass,String field,String value){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        FuzzyQueryBuilder fuzzyQueryBuilder=new FuzzyQueryBuilder(field,value);
        searchSourceBuilder.query(fuzzyQueryBuilder);
        return getResults(searchSourceBuilder,indexName,tClass);
    }

    /**
     * 聚合查询  todo  --->这些东西,其实封装不太好封装,灵活使用api吧,根据自己的业务真实的去封装
     */
    public static <T> List<T> aggDoc(String indexName, Class<T> tClass,String field){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("agg").field(field);
        searchSourceBuilder.aggregation(aggregationBuilder);
        return getResults(searchSourceBuilder,indexName,tClass);
    }
    /**
     * 分组统计
     */
    public static <T> List<T> groupDoc(String indexName, Class<T> tClass,String field){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("agg").field(field);
        searchSourceBuilder.aggregation(aggregationBuilder);
        return getResults(searchSourceBuilder,indexName,tClass);
    }

    /**
     * 通用查询,其他的不过是添加相应的条件罢了
     * @param searchSourceBuilder
     * @param indexName
     * @param tClass
     * @return
     * @param <T>
     */
    private static <T> List<T> getResults(SearchSourceBuilder searchSourceBuilder,String indexName,Class<T> tClass){
        SearchRequest searchRequest =new SearchRequest();
        searchRequest.indices(indexName);
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        SearchHits hits = search.getHits();

        List list =new ArrayList<T>();
        hits.forEach(hit -> {
            String sourceAsString = hit.getSourceAsString();
            T object = JsonObjUtil.toObject(sourceAsString, tClass);
            list.add(object);
        });
        return list;
    }
}
